昨天玩了一下路由,今天在回來看 UI,我會將頁面上需要重複利用的樣式抽出來,在新建的 components 資料夾中保存,以前吃過樣式跟功能過度耦合的痛苦,逐漸養成了這個習慣。每個人思考元件的方式可能有所不同,我就分享一下我自己的思路是怎麼運轉的。
操作邏輯跟頁面對不上是一件很可怕的事,如果使用者在操作到需要存檔的地方,卻沒有存檔的按鈕可以用,那會有多尷尬,用現實中的情境來對比,就是開心的用馬桶拉完屎之後才發現沒有沖水的桿子,差不多就是那種感覺...
也許,用水桶裝水來沖可以暫時緩解沒辦法沖水的問題,沒有存檔按鈕的使用者也可以用一通電話請,給資訊人員要輸入的資料跟請他幫忙存檔。
但不管怎樣,應該會先被使用者痛打一輪,一輪沒死透還要打兩輪。
為了示範,我先把一個小按鈕從 DefaultLayout 拆出來,就是 Menu 的那兩個按鈕。
新增 components 資料夾在 src 底下
新增 Button.tsx :
import React from "react";
const Button = ({ children, className }) => {
return (
<button className={`px-[8px] py-[2px] border rounded ${className}`}>
{children}
</button>
);
};
export default Button;
...
<div className="flex justify-between items-center shadow px-[20px] py-[20px]">
<h1 className="text-[30px] font-medium">
<Link to="/">MyNote</Link>
</h1>
<div>
<Button className="mr-[8px]">
<Link to="/dashboard">Dashboard</Link>
</Button>
<Button className="mr-[8px]">
<Link to="/todo">Todos</Link>
</Button>
</div>
</div>
...
現在我們就有一個自己的 Button 元件,以後想要一個這種樣式的 Button,就直接引入就好囉!
因為輸入到的 Button.tsx 的屬性 children, className 隱含著any
型別,因為我們並沒有給這些屬性設定型別,預設就是any
,所以 typescript 會報錯。
先到根目錄的 tsconfig.json 將這個報錯關閉吧,只要加上"noImplicitAny": false
就可以了。
{
"compilerOptions": {
"noImplicitAny": false,// 添加這一行
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": [
"src"
]
}
tip 對 typescript 不太了解的小夥伴,可以來看看這個中文教學,我剛入門的時候就是看這個。
通常我會跟路由來搭配使用,會使用到 react-router-dom 的 <Outlet>
。
在 Day-11 的示範當中有做過一次。
但其實還有另一個使用方式,就是在裡面放元素的容器,跟 component 相對的,就是放 container,例如 TodoPage 最外層的 ,再利用 children 來傳入子元件。
以目前的專案來看,/todo 對上 pages 的 TodoPage.tsx,然後 /dashboard 對上 DashboardPage.tsx,目前的頁面數量少,架構簡單,跟路由很輕鬆地就能對上。
為了示範 pages 如何跟路由對上,我跟大家分享我目前手邊在做的專案,它的資料夾結構 :
pages,裡面每一個都是資料夾 :
├─case
├─client
├─dispatch
├─login
├─noMatch
├─renewal
└─todo
App.tsx
<Routes>
<Route path="/" element={<DefaultLayout />}>
<Route index element={<TodoPage />}></Route>
<Route path="todo" element={<TodoPage />}>
...
</Route>
<Route path="case" element={<CasePage />}></Route>
<Route path="case/list" element={<CasePage />}></Route>
<Route path="case/repeat" element={<CaseRepeatPage />}></Route>
<Route path="client" element={<ClientPage />}></Route>
<Route path="dispatch" element={<DispatchPage />}></Route>
<Route path="renewal" element={<RenewalPage />}>
...
</Route>
</Routes>
拆元件的思路與操作可能會有二到三篇,在這個章節裡面我的流程會很 free,看起來就像我想到什麼我就寫成一段,寫一寫,又想到一個觀念,又增加新的一段,這很接近我實際上在做的時候會發生的事。
其實要把人做一件事情的流程(發散跳躍時快時慢,但最終會完成)做成一篇文章(一段接一段順序的敘述),有點難度,所以我的文章不太像教科書那樣會區分每個知識點,區分得很開。
看不太明白可以直接問我,如果有什麼想勘誤指教的,或者看不太懂得部分,都歡迎留言交流,謝謝大家。